﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "GcmpDatabase.h"
#include "GbmpGuid.h"
#include "DevServiceHeaders.h"
#include <functional>
#include <unordered_set>

// 定义文档升级例程开始
#define DEFINE_DOC_UPGRADER_BEGIN(ID, Name, Routine) \
    gcmp::OneTimeInitializer s_ndbDocUpgrader##Name##Initializer([]() { gcmp::OwnerPtr<gcmp::NdbDocUpgrader> opNdbDocUpgrader = NEW_AS_OWNER_PTR(gcmp::NdbDocUpgrader, ID, WSTRING_OF(Name), Routine);

// 定义直接依赖的例程。放在DEFINE_DOC_UPGRADER_BEGIN/DEFINE_DOC_UPGRADER_END之间，没有依赖项不用定义，有几个依赖项就定义几次。
#define DEFINE_DOC_UPGRADER_DEPENDENCY(PreID) \
    opNdbDocUpgrader->AddPreId(PreID);

// 定义文档升级例程结束
#define DEFINE_DOC_UPGRADER_END() \
    gcmp::NdbDocUpgradeManager::GetInstance()->AddDocUpgrader(TransferOwnership(opNdbDocUpgrader)); })

#pragma warning (push)
#pragma warning (disable:4251)

namespace gcmp
{
    // 文档升级。在文档的所有对象升级完之后调用，处理对象间的升级
    class GCMP_DATABASE_EXPORT NdbDocUpgrader
    {
    public:
        typedef std::function<void(void*)> NdbDocUpgraderRoutine;

        typedef GuidUnorderedSet NdbDocUpgraderIDs;

        NdbDocUpgrader(
            const Guid& id,
            const std::wstring& name,
            NdbDocUpgraderRoutine routine
        );

        const Guid& GetId() const { return m_id; }

        const NdbDocUpgraderIDs& GetPreIds() const { return m_preIds; }

        void AddPreId(const Guid& preId) { m_preIds.insert(preId); }

        const std::wstring& GetName() const { return m_name; }

        void Execute(void * pParam) const;

        std::wstring DumpAsString() const;

    private:
        Guid                  m_id;
        NdbDocUpgraderIDs     m_preIds; // 所依赖的其它Upgraders的ID，可为空集
        std::wstring          m_name;
        NdbDocUpgraderRoutine m_routine;
    };

    class GCMP_DATABASE_EXPORT NdbDocUpgradeManager
    {
        CANNOT_COPY_OR_ASSIGN(NdbDocUpgradeManager)

    public:
        static NdbDocUpgradeManager * GetInstance();

        NdbDocUpgradeManager();

        // 所有的代码中的DocUpgrader都要通过此接口被NdbDocUpgradeManager去Own
        void AddDocUpgrader(OwnerPtr<NdbDocUpgrader> opDocUpgrader);
        const std::vector<OwnerPtr<NdbDocUpgrader> >& GetAllDocUpgraders() const;

        // 如果返回true，表示DocUpgrader都执行完成；返回false表示无法找到一个合适的顺序去执行;
        // hasUpgraderExecuted 是否有文档升级执行了
        bool FilterOutAndExecute(const NdbDocUpgrader::NdbDocUpgraderIDs& toBeExcluded, void * pEnvironmentOfUpgraderRoutine, bool& hasUpgraderExecuted) const;

        // 调试用，以.dot格式打印Upgrader以及其关系图
        void DumpAllInDotFormat() const;

    private:
        const NdbDocUpgrader * GetUpgraderById(const Guid& id) const;

        // 如果返回true，则排好序的结果在sorted当中，结果不唯一；返回false表示无法找到一个合适的排序
        bool ToplogicalSortAll(std::vector<Guid>& sorted) const;

        std::vector<OwnerPtr<NdbDocUpgrader> > m_allDocUpgraders;
    };
}

#pragma warning (pop)

